diff options
Diffstat (limited to 'cloud/app/src/routes/workspace/[id].tsx')
| -rw-r--r-- | cloud/app/src/routes/workspace/[id].tsx | 272 |
1 files changed, 160 insertions, 112 deletions
diff --git a/cloud/app/src/routes/workspace/[id].tsx b/cloud/app/src/routes/workspace/[id].tsx index abada1c89..bfeb06884 100644 --- a/cloud/app/src/routes/workspace/[id].tsx +++ b/cloud/app/src/routes/workspace/[id].tsx @@ -49,7 +49,7 @@ const createPortalUrl = action(async (returnUrl: string) => { return withActor(() => Billing.generatePortalUrl({ returnUrl })) }, "portalUrl") -export default function() { +export default function () { const actor = createAsync(() => getActor()) onMount(() => { console.log("MOUNTED", actor()) @@ -154,126 +154,174 @@ export default function() { } return ( - <div> - <h1>Actor</h1> - <div>{JSON.stringify(actor())}</div> - <h1>API Keys</h1> - <Show - when={!showCreateForm()} - fallback={ - <div data-slot="create-form"> - <input - data-component="input" - type="text" - placeholder="Enter key name" - value={keyName()} - onInput={(e) => setKeyName(e.currentTarget.value)} - onKeyPress={(e) => e.key === "Enter" && handleCreateKey()} - /> - <div data-slot="form-actions"> - <button - color="primary" - disabled={createKeySubmission.pending || !keyName().trim()} - onClick={handleCreateKey} - > - {createKeySubmission.pending ? "Creating..." : "Create"} - </button> - <button - color="ghost" - onClick={() => { - setShowCreateForm(false) - setKeyName("") - }} - > - Cancel - </button> - </div> - </div> - } - > - <button - color="primary" - onClick={() => { - console.log("clicked") - setShowCreateForm(true) - }} - > - Create API Key - </button> - </Show> - <div data-slot="key-list"> - <For - each={keys()} + <div data-slot="root"> + {/* Actor Section */} + <section data-slot="actor-section"> + <div data-slot="section-title"> + <h1>Actor</h1> + <p>Current authenticated user information and session details.</p> + </div> + <div>{JSON.stringify(actor())}</div> + </section> + + {/* API Keys Section */} + <section data-slot="keys-section"> + <div data-slot="section-title"> + <h1>API Keys</h1> + <p>Manage your API keys for accessing opencode services.</p> + </div> + <Show + when={!showCreateForm()} fallback={ - <div data-slot="empty-state"> - <p>Create an API key to access opencode gateway</p> + <div data-slot="create-form"> + <input + data-component="input" + type="text" + placeholder="Enter key name" + value={keyName()} + onInput={(e) => setKeyName(e.currentTarget.value)} + onKeyPress={(e) => e.key === "Enter" && handleCreateKey()} + /> + <div data-slot="form-actions"> + <button + color="primary" + disabled={createKeySubmission.pending || !keyName().trim()} + onClick={handleCreateKey} + > + {createKeySubmission.pending ? "Creating..." : "Create"} + </button> + <button + color="ghost" + onClick={() => { + setShowCreateForm(false) + setKeyName("") + }} + > + Cancel + </button> + </div> </div> } > - {(key) => ( - <div data-slot="key-item"> - <div data-slot="key-info"> - <div data-slot="key-name">{key.name}</div> - <div data-slot="key-value">{formatKey(key.key)}</div> - <div data-slot="key-meta"> - Created: {formatDate(key.timeCreated)} - {key.timeUsed && ` • Last used: ${formatDate(key.timeUsed)}`} - </div> + <button + color="primary" + onClick={() => { + console.log("clicked") + setShowCreateForm(true) + }} + > + Create API Key + </button> + </Show> + <div data-slot="key-list"> + <For + each={keys()} + fallback={ + <div data-slot="empty-state"> + <p>Create an API key to access opencode gateway</p> </div> - <div data-slot="key-actions"> - <button color="ghost" onClick={() => copyToClipboard(key.key)} title="Copy API key"> - Copy - </button> - <button color="ghost" onClick={() => handleDeleteKey(key.id)} title="Delete API key"> - Delete - </button> + } + > + {(key) => ( + <div data-slot="key-item"> + <div data-slot="key-info"> + <div data-slot="key-name">{key.name}</div> + <div data-slot="key-value">{formatKey(key.key)}</div> + <div data-slot="key-meta"> + Created: {formatDate(key.timeCreated)} + {key.timeUsed && ` • Last used: ${formatDate(key.timeUsed)}`} + </div> + </div> + <div data-slot="key-actions"> + <button color="ghost" onClick={() => copyToClipboard(key.key)} title="Copy API key"> + Copy + </button> + <button color="ghost" onClick={() => handleDeleteKey(key.id)} title="Delete API key"> + Delete + </button> + </div> </div> - </div> - )} - </For> - </div> + )} + </For> + </div> + </section> - <h1>Balance</h1> - <p>Manage your billing and add credits to your account.</p> - <p> - {(() => { - const balanceStr = ((billingInfo()?.billing?.balance ?? 0) / 100000000).toFixed(2) - return `$${balanceStr === "-0.00" ? "0.00" : balanceStr}` - })()} - </p> - <button color="primary" disabled={isLoading()} onClick={handleBuyCredits}> - {isLoading() ? "Loading..." : "Buy Credits"} - </button> + {/* Balance Section */} + <section data-slot="balance-section"> + <div data-slot="section-title"> + <h1>Balance</h1> + <p>Manage your billing and add credits to your account.</p> + </div> + <div data-slot="balance"> + <p> + {(() => { + const balanceStr = ((billingInfo()?.billing?.balance ?? 0) / 100000000).toFixed(2) + return `$${balanceStr === "-0.00" ? "0.00" : balanceStr}` + })()} + </p> + <button color="primary" disabled={isLoading()} onClick={handleBuyCredits}> + {isLoading() ? "Loading..." : "Buy Credits"} + </button> + </div> + </section> - <h1>Payments History</h1> - <p>Your recent payment transactions.</p> - <For each={billingInfo()?.payments} fallback={<p>No payments found.</p>}> - {(payment) => ( - <div data-slot="payment-item"> - <span data-slot="payment-id">{payment.id}</span> - {" | "} - <span data-slot="payment-amount">${((payment.amount ?? 0) / 100000000).toFixed(2)}</span> - {" | "} - <span data-slot="payment-date">{new Date(payment.timeCreated).toLocaleDateString()}</span> - </div> - )} - </For> + {/* Payments Section */} + <section data-slot="payments-section"> + <div data-slot="section-title"> + <h1>Payments History</h1> + <p>Your recent payment transactions.</p> + </div> + <div data-slot="payments-list"> + <For + each={billingInfo()?.payments} + fallback={ + <div data-slot="empty-state"> + <p>No payment history yet. Your payments will appear here after your first purchase.</p> + </div> + } + > + {(payment) => ( + <div data-slot="payment-item"> + <span data-slot="payment-id">{payment.id}</span> + {" | "} + <span data-slot="payment-amount">${((payment.amount ?? 0) / 100000000).toFixed(2)}</span> + {" | "} + <span data-slot="payment-date">{new Date(payment.timeCreated).toLocaleDateString()}</span> + </div> + )} + </For> + </div> + </section> - <h1>Usage History</h1> - <p>Your recent API usage and costs.</p> - <For each={billingInfo()?.usage} fallback={<p>No usage found.</p>}> - {(usage) => ( - <div data-slot="usage-item"> - <span data-slot="usage-model">{usage.model}</span> - {" | "} - <span data-slot="usage-tokens">{usage.inputTokens + usage.outputTokens} tokens</span> - {" | "} - <span data-slot="usage-cost">${((usage.cost ?? 0) / 100000000).toFixed(4)}</span> - {" | "} - <span data-slot="usage-date">{new Date(usage.timeCreated).toLocaleDateString()}</span> - </div> - )} - </For> + {/* Usage Section */} + <section data-slot="usage-section"> + <div data-slot="section-title"> + <h1>Usage History</h1> + <p>Your recent API usage and costs.</p> + </div> + <div data-slot="usage-list"> + <For + each={billingInfo()?.usage} + fallback={ + <div data-slot="empty-state"> + <p>No API usage yet. Your usage history will appear here after your first API calls.</p> + </div> + } + > + {(usage) => ( + <div data-slot="usage-item"> + <span data-slot="usage-model">{usage.model}</span> + {" | "} + <span data-slot="usage-tokens">{usage.inputTokens + usage.outputTokens} tokens</span> + {" | "} + <span data-slot="usage-cost">${((usage.cost ?? 0) / 100000000).toFixed(4)}</span> + {" | "} + <span data-slot="usage-date">{new Date(usage.timeCreated).toLocaleDateString()}</span> + </div> + )} + </For> + </div> + </section> </div> ) } |
